package app

import (
	"encoding/json"
	"gin-demo/pkg/e"
	gogrpc "gin-demo/pkg/grpc"
	"gin-demo/pkg/logging"
	"gin-demo/pkg/setting"
	"github.com/golang/protobuf/proto"
	spb "google.golang.org/genproto/googleapis/rpc/status"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"net/http"
	"time"
)

// grpc
const (
	PluginsServerDialTimeout = 3 * time.Second // timeout
)

// NewGRPCConn conn
func NewGRPCConn() (conn *grpc.ClientConn, err error) {
	conn, err = gogrpc.NewClientWithConfigAndAddr(setting.PluginsConfig, setting.PluginsConfig.RegAddress)
	if err != nil {
		logging.Error(err)
		err = NewResponseErr(http.StatusOK, e.ERROR, nil)
		return
	}
	return
}

// ReleaseGRPCConn release
func ReleaseGRPCConn(conn *grpc.ClientConn) (err error) {
	return conn.Close()
}

// Err error
type Err struct {
	Code    int32       `json:"code"`
	Message string      `json:"message"`
	Data    interface{} `json:"data"`
}

// Error interface error
func (e *Err) Error() (msg string) {
	msgBytes, _ := json.Marshal(e)

	return string(msgBytes)
}

// NewGRPCError grpc error
func NewGRPCError(httpCode, errCode int, data proto.Message) (err error) {
	//return &Err{Code: int32(errCode), Message: e.GetMsg(errCode), Data: data}
	s := &spb.Status{Code: int32(errCode), Message: e.GetMsg(errCode), Details: nil}
	return status.ErrorProto(s)
}

// FromGRPCError grpc error
func FromGRPCError(err error) (code int, msg string) {
	if err == nil {
		return
	}
	code = e.Unknown
	msg = err.Error()

	s, ok := status.FromError(err)
	if !ok {
		return
	}
	code = int(s.Code())
	msg = s.Message()

	switch s.Code() {
	case codes.DeadlineExceeded:
		code = e.DialTimeout
		msg = e.GetMsg(code)
	case codes.Unavailable:
		code = e.PluginsServerUnavailable
		msg = e.GetMsg(code)
	}
	if s.Code() == codes.DeadlineExceeded {
		code = e.DialTimeout
		msg = e.GetMsg(code)
	}

	//var s2 = &Err{}
	//if err := json.Unmarshal([]byte(Msg), s2); err != nil {
	//	err = nil
	//	return
	//}
	//code = int(s2.Code)
	//Msg = s2.Message

	return
}
